In [47]:
import re
from collections import defaultdict
PARSE = re.compile("([A-Za-z]+): capacity ([-0-9]+), durability ([-0-9]+), flavor ([-0-9]+), texture ([-0-9]+), calories ([-0-9]+)")
def load_ingredients(ingredients):
result = {}
properties = defaultdict(dict)
for i in ingredients:
name, capacity, durability, flavor, texture, calories = PARSE.match(i).groups()
result[name] = {
'capacity': int(capacity),
'durability': int(durability),
'flavor': int(flavor),
'texture': int(texture),
'calories': int(calories)
}
for k, r in result.items():
for p, v in r.items():
properties[p][k] = v
return result, properties
def score(elements, properties):
values = {k: v for k, v in elements}
s = 1
for p, v in properties.items():
if p == 'calories':
continue
s *= max(sum([values[k]*w for k, w in v.items()]), 0)
return s
def combinations(elements, total):
if len(elements) == 0:
yield []
elif len(elements) == 1:
yield [(elements[0], total)]
else:
first_element = elements[0]
for i in range(0, total+1):
for c in combinations(elements[1:], total - i):
yield [(first_element, i)] + c
def find_max_score(ingredients, properties, total, calories=None):
max_combinations = []
max_score = -1
for c in combinations(list(ingredients), total):
if calories:
total_calories = sum([properties['calories'][a]*v for a, v in c])
if total_calories != calories:
continue
s = score(c, properties)
if s == max_score:
max_combinations.append(c)
elif s > max_score:
max_combinations = [c]
max_score = s
return max_score, max_combinations
In [45]:
# Test example
example = [
"Butterscotch: capacity -1, durability -2, flavor 6, texture 3, calories 8",
"Cinnamon: capacity 2, durability 3, flavor -2, texture -1, calories 3"
]
ingredients, properties = load_ingredients(example)
find_max_score(ingredients, properties, 100)
Out[45]:
In [46]:
# Real input
with open("day15/input.txt", "rt") as fd:
ingredients, properties = load_ingredients(fd)
print(find_max_score(ingredients, properties, 100))
In [48]:
# Test example
ingredients, properties = load_ingredients(example)
find_max_score(ingredients, properties, 100, calories=500)
Out[48]:
In [49]:
# Real input
with open("day15/input.txt", "rt") as fd:
ingredients, properties = load_ingredients(fd)
print(find_max_score(ingredients, properties, 100, calories=500))
In [ ]: